package model.trivial_pursuit;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;

import database.Clause;
import database.ValuedAttribute;

import model.DbTable;

/**
 * Méthode représentant une 'carte' de jeu, mais avec une seule question (et sa réponse)
 * 		(contrairement à la version plateau)
 * @author Aubry Pirian
 *
 */
public class Card extends DbTable {
	
	private int id;				// Identifiant de la carte
	private int theme;			// Identifiant du theme
	private int color;			// Numero de la couleur
	private int level;			// Niveau de la question
	private String question;	// Question
	private String answer;		// Réponse

	/**
	 * Constructeur de carte vide
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws SQLException 
	 * @throws ClassNotFoundException : impossible d'accéder au driver JDBC
	 */
	public Card() throws ClassNotFoundException, SQLException, NoSuchFieldException {
		super(TPParams.CARD_TABLE);
	}
	
	/**
	 * Constructeur de la carte n° id
	 * @param id
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws SQLException 
	 * @throws ClassNotFoundException : impossible d'accéder au driver JDBC
	 */
	public Card(int id) throws ClassNotFoundException, SQLException, NoSuchFieldException {
		super(TPParams.CARD_TABLE);
		this.id = id;
		try {
			this.read(id);
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
	}
	
	/**
	 * Méthode récupérant les informations de la carte n° id 
	 * @param id : numéro de la carte
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 */
	private void read (int id) throws SQLException, NoSuchFieldException {
		Clause where;
		try {
			where = new Clause( new ValuedAttribute("id",id));
		} catch (NoSuchFieldException e) {
			throw e;
		}
		ResultSet rs;
		try {
			rs = this.idbc.select(this.tableName,where);
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
		try {
			if (rs.next()) {
				try {
					this.theme = rs.getInt("theme");
					this.color = rs.getInt("color");
					this.level = rs.getInt("level");
					this.question = rs.getString("question");
					this.answer = rs.getString("answer");
				} catch (SQLException e) {
					throw e;
				}
			}
		} catch (SQLException e) {
			throw e;
		}
	}
	
	/**
	 * Méthode retournant le plus grand numéro de carte
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 */
	private int readMaxId () throws SQLException, NoSuchFieldException {
		LinkedList<String> attrs = new LinkedList<String>();
		//FIXME : voir comment trouver le MAX() avec jdbc
		//attrs.add("MAX(id)");
		LinkedList<String> orderBy = new LinkedList<String>();
		orderBy.add("-id");
		ResultSet rs;
		try {
			rs = this.idbc.select(this.tableName,attrs,null,orderBy);
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
		try {
			if (rs.next()) {
				try {
					return rs.getInt("id");
				} catch (SQLException e) {
					throw e;
				}
			} else {
				return -1;
			}
		} catch (SQLException e) {
			throw e;
		}
	}
	
	/**
	 * Méthode enregistrant la carte avec les valeurs données
	 * @param theme			: theme de la carte
	 * @param color			: numéro de la couleur
	 * @param question		: question
	 * @param answer		: réponse
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws ClassNotFoundException : impossible d'accéder au driver JDBC
	 */
	public void create (int theme, int color, int level, String question, String answer) throws SQLException, NoSuchFieldException, ClassNotFoundException {
		int newId;
		try {
			newId = this.readMaxId() +1;
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
		LinkedList<ValuedAttribute> values = new LinkedList<ValuedAttribute>();
		try {
			new Theme(theme);
		} catch (ClassNotFoundException e) {
			throw e;
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
		if (color<0 || color>=6) throw new NoSuchFieldException("Couleur invalide.");
		try {
			values.add( new ValuedAttribute("id",newId) );
			values.add( new ValuedAttribute("theme",theme) );
			values.add( new ValuedAttribute("color",color) );
			if ( level>=TPParams.MIN_LEVEL && level<=TPParams.NB_LEVELS-TPParams.MIN_LEVEL ) {
				values.add( new ValuedAttribute("level",level) );
			} else {
				values.add( new ValuedAttribute("level",TPParams.MIN_LEVEL) );
			}
			values.add( new ValuedAttribute("question",question) );
			values.add( new ValuedAttribute("answer",answer) );
		} catch (NoSuchFieldException e) {
			throw e;
		}
		try {
			this.idbc.insert(this.tableName, values);
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
		this.id = newId;
		this.theme = theme;
		this.color = color;
		this.level = level;
		this.question = question;
		this.answer = answer;
//		this.read(newId);
	}
	
	/**
	 * Méthode retournant la clause identifiant la carte dans la table
	 * @return Clause where
	 * @throws NoSuchFieldException : paramètre non valide
	 */
	private Clause getWhere() throws NoSuchFieldException {
		try {
			return new Clause( new ValuedAttribute("id",""+this.id) );
		} catch (NoSuchFieldException e) {
			throw e;
		}
	}
	
	
	/**
	 * Méthode enregistrant la carte avec les valeurs données
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws ClassNotFoundException : impossible d'accéder au driver JDBC
	 */
	public void delete() throws SQLException, NoSuchFieldException, ClassNotFoundException {
		this.idbc.delete(TPParams.CARD_TABLE, this.getWhere());
	}
	
	
	/**
	 * Accesseur du numéro
	 * @return numéro de la carte
	 */
	public int getId() { return this.id; }
	/**
	 * Accesseur du theme
	 * @return theme de la carte
	 */
	public int getTheme() { return this.theme; }
	/**
	 * Accesseur de la couleur
	 * @return couleur de la carte
	 */
	public int getColor() { return this.color; }
	/**
	 * Accesseur du niveau
	 * @return niveau de la question
	 */
	public int getLevel() { return this.level; }
	/**
	 * Accesseur de la question
	 * @return question
	 */
	public String getQuestion() { return this.question; }
	/**
	 * Accesseur de la réponse
	 * @return réponse
	 */
	public String getAnswer() { return this.answer; }
	
	/**
	 * Modifieur générique
	 * @param field : champ à modifier
	 * @param value : valeur à attribuer
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 */
	private void setValue (String field, Object value) throws SQLException, NoSuchFieldException {
		LinkedList<ValuedAttribute> values = new LinkedList<ValuedAttribute>();
		try {
			values.add( new ValuedAttribute(field,value) );
		} catch (NoSuchFieldException e) {
			throw e;
		}
		try {
			this.idbc.update(this.tableName, values,this.getWhere("id",this.id));
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
	}

	/**
	 * Modifieur du numéro de la carte
	 * @param id : nouveau numéro
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws SQLException 
	 */
	public void setId(int id) throws NoSuchFieldException, SQLException {
		if (id>=0) {
			try {
				this.setValue("id",id);
			} catch (SQLException e) {
				throw e;
			} catch (NoSuchFieldException e) {
				throw e;
			}
			this.id=id;
		} else throw new NoSuchFieldException("Numéro de carte non valide.");
	}
	
	/**
	 * Modifieur du theme de la carte
	 * @param theme : nouveau theme
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws SQLException
	 */
	public void setTheme(int theme) throws NoSuchFieldException, SQLException {
		if (theme>=0) {
			try {
				this.setValue("theme",theme);
			} catch (SQLException e) {
				throw e;
			} catch (NoSuchFieldException e) {
				throw e;
			}
			this.theme = theme;
		} else throw new NoSuchFieldException("Numéro de theme non valide.");
	}
	
	/**
	 * Modifieur du theme de la carte
	 * @param theme : nouveau theme
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws SQLException 
	 * @throws ClassNotFoundException 
	 */
	public void setTheme(String theme) throws NoSuchFieldException, SQLException, ClassNotFoundException {
		try {
			Theme t = new Theme(theme);
			this.theme = t.getId();
		} catch (ClassNotFoundException e) {
			throw e;
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
	}
	
	/**
	 * Modifieur de la couleur de la carte
	 * @param color : nouvelle couleur
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 */
	public void setColor(int color) throws SQLException, NoSuchFieldException {
		if ( color>=TPParams.MIN_COLOR && color<TPParams.MIN_COLOR+TPParams.NB_COLORS ) {
			try {
				this.setValue("color",color);
			} catch (SQLException e) {
				throw e;
			} catch (NoSuchFieldException e) {
				throw e;
			}
			this.color = color;
		} else throw new NoSuchFieldException("Numéro de couleur non valide.");
	}
	
	/**
	 * Modifieur de la couleur de la carte
	 * @param color : nouvelle couleur
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 */
	public void setColor(String color) throws SQLException, NoSuchFieldException {
		if ( color==null || color.length()==0)
			throw new NoSuchFieldException("Nom de couleur vide");
		int cc = TPParams.COLORS.length;
		for (int c=0; c<cc; c++) {
			if (utils.StrUtils.inArray(TPParams.COLORS[c],color,false)) {
				this.setColor(c+1);
				return;
			}
		}
		throw new NoSuchFieldException("Couleur inconnue");
	}
	
	/**
	 * Modifieur du niveau de la carte
	 * @param level : nouveau niveau
	 * @throws SQLException 
	 * @throws NoSuchFieldException : paramètre non valide
	 */
	public void setLevel(int level) throws SQLException, NoSuchFieldException {
		if ( level>=TPParams.MIN_LEVEL && level<TPParams.MIN_LEVEL+TPParams.NB_LEVELS ) {
			try {
				this.setValue("level",level);
			} catch (SQLException e) {
				throw e;
			} catch (NoSuchFieldException e) {
				throw e;
			}
			this.level = level;
		} else throw new NoSuchFieldException("Niveau non valide.");
	}
	
	/**
	 * Modifier de la question
	 * @param question : nouvelle question
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws SQLException 
	 */
	public void setQuestion(String question) throws NoSuchFieldException, SQLException {
		if ( question==null) throw new NoSuchFieldException("Question vide.");
		if (question.length()<TPParams.SIZES_CARD_QUESTION[0]) throw new NoSuchFieldException("Question trop courte.");
		//if (question.length()>Params.SIZES_THEME_QUESTION[1]) throw new NoSuchFieldException("Question trop longue.");
		try {
			this.setValue("question",question);
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
		this.question = question;
	}
	/**
	 * Modifieur de la réponse
	 * @param answer : nouvelle réponse
	 * @throws NoSuchFieldException : paramètre non valide
	 * @throws SQLException 
	 */
	public void setAnswer(String answer) throws NoSuchFieldException, SQLException {
		if (answer==null) throw new NoSuchFieldException("Réponse vide.");
		if (answer.length()<TPParams.SIZES_CARD_ANSWER[0]) throw new NoSuchFieldException("Réponse trop courte.");
		//if (answer.length()>Params.SIZES_THEME_ANSWER[1]) throw new NoSuchFieldException("Réponse trop longue.");
		try {
			this.setValue("answer",answer);
		} catch (SQLException e) {
			throw e;
		} catch (NoSuchFieldException e) {
			throw e;
		}
		this.answer = answer;
	}
	
	
	
	@Override
	public String toString () {
		return this.id+":"+this.theme+":"+this.color+":"+this.level
			+":[["+this.question+"]]"
			+":[["+this.answer+"]]";
	}
	
	
	public static void main (String[] args) {
		Card c;
			try {
				c = new Card();
				c.create(1, 4, 2, "comment?", "non");
				System.out.println(c);
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NoSuchFieldException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}
	
	

}
